/**
 * 
 */
package br.ufal.ic.sd.project.server.core;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author keven andrade
 *
 */
public class Channel {
    
    	private String strIP;
	private int intPort;
	private Socket objClientSocket;
	private ServerSocket objServerSocket;
	private ObjectInputStream objInputStreamIn;
	private ObjectOutputStream objOutputStreamOut;
	
	/**
	 * Channel's Constructor 
	 * @param strIP
	 * @param intPort
	 */
	public Channel(String strIP, int intPort){
		
	    this.strIP = strIP;
	    this.intPort = intPort;
	}
	
	/**
	 * Channel's Constructor 
	 */
	public Channel(){
		
	}
	
	//=========================================================== Getters and Setters =========================================================

	
	/**
	 * @return the strIP
	 */
	public String getStrIP() {
	    return strIP;
	}

	/**
	 * @param strIP the strIP to set
	 */
	public void setStrIP(String strIP) {
	    this.strIP = strIP;
	}

	/**
	 * @return the intPort
	 */
	public int getIntPort() {
	    return intPort;
	}

	/**
	 * @param intPort the intPort to set
	 */
	public void setIntPort(int intPort) {
	    this.intPort = intPort;
	}

	/**
	 * @return the objClientSocket
	 */
	public Socket getObjClientSocket() {
	    return objClientSocket;
	}

	/**
	 * @param objClientSocket the objClientSocket to set
	 */
	public void setObjClientSocket(Socket objClientSocket) {
	    this.objClientSocket = objClientSocket;
	}

	/**
	 * @return the objInputStreamIn
	 */
	public ObjectInputStream getObjInputStreamIn() {
	    return objInputStreamIn;
	}

	/**
	 * @param objInputStreamIn the objInputStreamIn to set
	 */
	public void setObjInputStreamIn(ObjectInputStream objInputStreamIn) {
	    this.objInputStreamIn = objInputStreamIn;
	}

	/**
	 * @return the objOutputStreamOut
	 */
	public ObjectOutputStream getObjOutputStreamOut() {
	    return objOutputStreamOut;
	}

	/**
	 * @param objOutputStreamOut the objOutputStreamOut to set
	 */
	public void setObjOutputStreamOut(ObjectOutputStream objOutputStreamOut) {
	    this.objOutputStreamOut = objOutputStreamOut;
	}
	
	
	/**
	 * @return the objServerSocket
	 */
	public ServerSocket getObjServerSocket() {
	    return objServerSocket;
	}

	/**
	 * @param objServerSocket the objServerSocket to set
	 */
	public void setObjServerSocket(ServerSocket objServerSocket) {
	    this.objServerSocket = objServerSocket;
	}
	
	//================================================================== Methods ===============================================================


	/**
	 * Open a connection with an particular server  using the server IP and the port
	 */
	public void connect() {
		
		try {
			this.objClientSocket = new Socket(this.getStrIP(), this.getIntPort());
			
			this.objOutputStreamOut = new ObjectOutputStream(this.objClientSocket.getOutputStream());
			this.objOutputStreamOut.flush();
			this.objInputStreamIn = new ObjectInputStream(this.objClientSocket.getInputStream());
			
		} catch (UnknownHostException e) {
			System.err.println("Connect Failed on host " + this.getStrIP());
		} catch (IOException e) {
			System.err.println("Connect Failed on host " + this.getStrIP());
		}
	}
	
	/**
	 * Close an existing connection with a server
	 */
	public void closeConnection() {
	    
	    try {
		this.objClientSocket.close();
	    } catch (IOException e) {
		System.err.println("System failed!");
		
	    }
	    
	    System.out.println("Connection closed");
	}
	
	/**
	 *@Method that read a sequence of bytes from the channel
	 */
	public int read(byte[] bytes) {
		
		try {
			
			return this.objInputStreamIn.read(bytes);

		} catch (IOException e) {
//		    System.err.println(e.getMessage());
		    System.err.println("Ooops!");
		}

		return -1;
	}

	/**
	 *@Method that read an object from the channel
	 *@return null in case of error
	 */
	public String read() {
		
		try {
			return this.objInputStreamIn.readObject().toString();
			
		} catch (IOException e) {
		    System.err.println("Ooops! System Error");
		} catch (ClassNotFoundException e) {
		    System.err.println("Ooops! System Error");
		}
		return null;
	}

	/**
	 *@Method that push a sequence bytes throw the communication channel 
	 */
	public void write(byte[] bytes, int i) {

		try {
			
			this.objOutputStreamOut.write(bytes, 0, i);
			this.objOutputStreamOut.flush();

		} catch (IOException e) {
//		    System.err.println(e.getMessage());
		    System.err.println("Ooops!");
		}
	}

	/**
	 *@Method that push a message throw the communication channel 
	 */
	public void write(String strMessage) {

		try {
			this.objOutputStreamOut.writeObject(strMessage);
			this.objOutputStreamOut.flush();

		} catch (IOException e) {
//		    System.err.println(e.getMessage());
		    System.err.println("Ooops!");
		}
	}

	public void close(){
	    
	    try {
		this.objClientSocket.close();
	    } catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	    }
	}

	public boolean isClosed() {
	    
	    if(this.objClientSocket.isClosed()){
		return true;
	    }else{
		return false;
	    }
	    
	    
	}
}
